package com.immediatus.util;

import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import static com.immediatus.graphics.util.OpenGLWrapper.BYTES_PER_FLOAT;

public class FastFloatBuffer{
    public final ByteBuffer Buffer;

    private static SoftReference<int[]> _weakIntArray = new SoftReference<int[]>(new int[0]);

    private final FloatBuffer _floatBuffer;
    private final IntBuffer _intBuffer;

    public FastFloatBuffer(final int _capacity){
        this.Buffer = ByteBuffer.allocateDirect((_capacity * BYTES_PER_FLOAT)).order(ByteOrder.nativeOrder());
        this._floatBuffer = this.Buffer.asFloatBuffer();
        this._intBuffer = this.Buffer.asIntBuffer();
    }

    public void flip(){
        this.Buffer.flip();
        this._floatBuffer.flip();
        this._intBuffer.flip();
    }

    public void put(final float item_){
        final ByteBuffer byteBuffer = this.Buffer;
        final IntBuffer intBuffer = this._intBuffer;

        byteBuffer.position(byteBuffer.position() + BYTES_PER_FLOAT);
        this._floatBuffer.put(item_);
        intBuffer.position(intBuffer.position() + 1);
    }

    public void put(final float[] data_){
        final int length = data_.length;

        int[] ia = _weakIntArray.get();
        if (ia == null || ia.length < length){
            ia = new int[length];
            _weakIntArray = new SoftReference<int[]>(ia);
        }

        for (int i = 0; i < length; i++){
            ia[i] = Float.floatToRawIntBits(data_[i]);
        }

        final ByteBuffer byteBuffer = this.Buffer;
        byteBuffer.position(byteBuffer.position() + BYTES_PER_FLOAT * length);
        final FloatBuffer floatBuffer = this._floatBuffer;
        floatBuffer.position(floatBuffer.position() + length);
        this._intBuffer.put(ia, 0, length);
    }

    public void put(final int[] data_){
        final ByteBuffer byteBuffer = this.Buffer;
        byteBuffer.position(byteBuffer.position() + BYTES_PER_FLOAT * data_.length);
        final FloatBuffer floatBuffer = this._floatBuffer;
        floatBuffer.position(floatBuffer.position() + data_.length);
        this._intBuffer.put(data_, 0, data_.length);
    }

    public static int[] convert(final float... data_){
        final int length = data_.length;
        final int[] id = new int[length];
        for (int i = 0; i < length; i++){
            id[i] = Float.floatToRawIntBits(data_[i]);
        }

        return id;
    }

    public void put(final FastFloatBuffer b_){
        final ByteBuffer byteBuffer = this.Buffer;
        byteBuffer.put(b_.Buffer);
        this._floatBuffer.position(byteBuffer.position() >> 2);
        this._intBuffer.position(byteBuffer.position() >> 2);
    }

    public int capacity(){
        return this._floatBuffer.capacity();
    }

    public int position(){
        return this._floatBuffer.position();
    }

    public void position(final int p_){
        this.Buffer.position(p_ * BYTES_PER_FLOAT);
        this._floatBuffer.position(p_);
        this._intBuffer.position(p_);
    }

    public FloatBuffer slice(){
        return this._floatBuffer.slice();
    }

    public int remaining(){
        return this._floatBuffer.remaining();
    }

    public int limit(){
        return this._floatBuffer.limit();
    }

    public void clear(){
        this.Buffer.clear();
        this._floatBuffer.clear();
        this._intBuffer.clear();
    }
}
